#include "../src/nominalembed.hh"

#include <cassert>
#include <iostream>

namespace
{
using namespace playerpiano;

struct LogPRatingTestDatum 
{ 
  struct
    {
      unsigned int      rating;
      float             alpha[4 * 2];
      float             tau[((2 * 4 - 2 + 1) * 2) / 2];
      unsigned int      true_label;
      float             logbeta;
    }                                   inputs;
  struct
    {
      float             logp;
      float             dlogbeta;
      float             ddlogbeta;
    }                                   outputs;
};

void
test_logprating (void)
{
  LogPRatingTestDatum data[] = 
    {{{2, {0.850929, 0.107237, 0.670178, 0.982617, 0.31533, 0.895524,  0.850625, 0.769172}, {0.520474, 0.707567, 0.982943, 0.0993117,  0.942415}, 3, 0.382297}, {-0.922746,  0.158445, -0.0664684}}, {{3, {0.448134, 0.219243, 0.677565,  0.12642, 0.706406, 0.371647, 0.568403, 0.275492}, {0.585786,  0.703645, 0.850844, 0.816614, 0.989584}, 3, 0.530684}, {-0.760093,  0.168993, -0.236512}}, {{0, {0.330369, 0.761158, 0.282016,  0.547741, 0.231057, 0.818743, 0.89972, 0.099607}, {0.773299,  0.640167, 0.572775, 0.497808, 0.794031}, 1,  0.938698}, {-2.11588, -0.965583, -1.36215}}, {{1, {0.986989,  0.537646, 0.0903864, 0.0878544, 0.170376, 0.548063, 0.559703,  0.757485}, {0.0119622, 0.590474, 0.366327, 0.912355, 0.514613}, 0,  0.449296}, {-2.35425, -1.13729, -1.42318}}, {{2, {0.593028,  0.519155, 0.874446, 0.876521, 0.0952198, 0.725123, 0.935748,  0.889532}, {0.847894, 0.00951104, 0.0750341, 0.0904087, 0.309938},  2, 0.743465}, {-0.4928,  0.378123, -0.0228723}}, {{2, {0.0630719, 0.563981, 0.719464,  0.377138, 0.150717, 0.0493674, 0.270167, 0.78411}, {0.393646,  0.906439, 0.239173, 0.504115, 0.131317}, 1, 0.271702}, {-1.04352,  0.222111,  0.0398117}}, {{2, {0.391279, 0.784959, 0.121806, 0.196668, 0.30087,  0.475021, 0.378341, 0.133596}, {0.00120337, 0.687522, 0.48539,  0.217093, 0.351317}, 1,  0.512601}, {-3.01517, -1.81866, -2.07778}}, {{0, {0.0917435,  0.528203, 0.444878, 0.273428, 0.587629, 0.396886, 0.173176,  0.882149}, {0.976508, 0.327649, 0.896739, 0.842912, 0.84439}, 0,  0.572092}, {-0.150661,  0.373985, -0.542924}}, {{0, {0.895535, 0.860032, 0.156869,  0.0867025, 0.678442, 0.508715, 0.644268, 0.994959}, {0.37084,  0.753354, 0.89066, 0.488691, 0.60466}, 1,  0.478274}, {-1.4733, -0.816871, -1.40142}}, {{2, {0.914152,  0.907412, 0.277011, 0.581535, 0.0712404, 0.0630212, 0.704918,  0.686}, {0.618216, 0.702493, 0.261884, 0.623257, 0.857318}, 1,  0.638657}, {-1.18133, 0.0447255, -0.128347}}};  

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      NominalEmbed nominal_embed (data[i].inputs.alpha,
                                  data[i].inputs.tau,
                                  0, // prioralpha_stddev
                                  0, // priortau_stddev
                                  2, // n_dims
                                  1, // n_workers
                                  4, // n_labels
                                  0); // n_items
      Rating rating = { 0, data[i].inputs.rating };
      float dlogbeta = drand48 ();
      float ddlogbeta = drand48 ();

      float logp = nominal_embed.logprating (rating, 
                                             data[i].inputs.true_label,
                                             exp (data[i].inputs.logbeta),
                                             dlogbeta,
                                             ddlogbeta);

      float megalogp = nominal_embed.logprating (rating, 
                                                 data[i].inputs.true_label,
                                                 exp (data[i].inputs.logbeta));

      assert (fabs (logp - data[i].outputs.logp) <=
              1e-4 * (1 + fabs (logp) + fabs (data[i].outputs.logp)) ||
              (std::cerr << i << " : " << logp << " ?= " << data[i].outputs.logp << std::endl,
               0));

      assert (fabs (megalogp - data[i].outputs.logp) <=
              1e-4 * (1 + fabs (megalogp) + fabs (data[i].outputs.logp)) ||
              (std::cerr << i << " : " << megalogp << " ?= " << data[i].outputs.logp << std::endl,
               0));

      assert (fabs (dlogbeta - data[i].outputs.dlogbeta) <=
              1e-4 * (1 + fabs (dlogbeta) + fabs (data[i].outputs.dlogbeta)) ||
              (std::cerr << i << " : " << dlogbeta << " ?= " << data[i].outputs.dlogbeta << std::endl,
               0));

      assert (fabs (ddlogbeta - data[i].outputs.ddlogbeta) <=
              1e-4 * (1 + fabs (ddlogbeta) + fabs (data[i].outputs.ddlogbeta)) ||
              (std::cerr << i << " : " << ddlogbeta << " ?= " << data[i].outputs.ddlogbeta << std::endl,
               0));
    }
}

#define n_workers 4
#define n_labels 5
#define n_dims 2

struct DFuncTestDatum 
{ 
  struct
    {
      float             alpha[n_dims * n_labels * n_workers];
      float             tau[((2 * n_labels - n_dims - 1) * n_dims) / 2];
      float             logbeta;
      float             pz[n_labels];
      Rating            rating;
    }                                   inputs;
  struct
    {
      float             dalpha[n_dims * n_labels * n_workers];
      float             dtau[((2 * n_labels - n_dims - 1) * n_dims) / 2];
    }                                   outputs;
};

void
test_dfunc (void)
{
  DFuncTestDatum data[] = 
    {{{{0.435102, 0.239067, 0.645028, 0.298803, 0.391479, 0.64199,  0.283713, 0.984398, 0.873624, 0.056035, 0.272995, 0.518897,  0.619653, 0.857944, 0.755556, 0.26364, 0.738521, 0.831791,  0.627432, 0.470633, 0.827875, 0.366309, 0.262933, 0.306029,  0.392773, 0.127242, 0.617905, 0.00722658, 0.00129427, 0.485251,  0.334192, 0.0228281, 0.12767, 0.429216, 0.0611971, 0.503932,  0.508018, 0.571272, 0.305641, 0.240291}, {0.67821, 0.941621,  0.373172, 0.415277, 0.463629, 0.548848, 0.24593},  0.797372, {0.456403, 0.547554, 0.760679, 0.46318, 0.433574}, {3,  1}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.158913, 0.0427566, 0.0671356,  1.45396, -0.0723284, -0.758871, -0.205295, -0.187396,  0.0515747, -0.550447}, {0.0671296, -0.0723267, -0.75887,  -0.205293, -0.187395, 0.0515756, -0.550447}}}, {{{0.419884, 0.331463,  0.401983, 0.929643, 0.911866, 0.760191, 0.0963416, 0.689352,  0.14237, 0.0207101, 0.418132, 0.919693, 0.200748, 0.647538,  0.00285532, 0.456064, 0.6519, 0.401608, 0.205483, 0.999661,  0.104346, 0.640929, 0.742303, 0.566087, 0.684462, 0.309467,  0.34032, 0.636444, 0.772596, 0.549276, 0.243978, 0.947092,  0.630226, 0.528566, 0.825847, 0.0273992, 0.429478, 0.881027,  0.822991, 0.571335}, {0.617508, 0.673232, 0.83849, 0.875205,  0.00558718, 0.98877, 0.529023},  0.534885, {0.369143, 0.216174, 0.979747, 0.290906, 0.422051}, {3,  2}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1.04707, -0.0195043, -0.0506115, -0.414548, -1.26094,  0.208342, -0.0678638, 0.0406941, 0.332342,  0.185016}, {-0.0506114, -1.26093, 0.208342, -0.0678638, 0.0406942,  0.332341, 0.185016}}}, {{{0.585948, 0.451182, 0.46506, 0.394652,  0.156469, 0.570154, 0.642068, 0.823317, 0.378891, 0.0907352,  0.0245605, 0.251643, 0.705659, 0.252245, 0.149356, 0.246055,  0.716888, 0.723222, 0.614471, 0.876912, 0.500714, 0.743475,  0.323565, 0.454861, 0.914766, 0.292293, 0.858506, 0.060209,  0.758297, 0.722139, 0.216437, 0.236892, 0.379406, 0.631404,  0.191877, 0.98525, 0.673747, 0.379158, 0.0425208,  0.739194}, {0.428049, 0.456145, 0.912461, 0.104484, 0.407421,  0.541378, 0.620168},  0.245979, {0.347212, 0.783081, 0.898029, 0.0295416, 0.11032}, {1,  3}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0740252, 0.4057, 0.0802814,  0.850992, -0.00953539, 0.453536, -0.391316, -2.0387, 0.246545,  0.328473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0}, {0.0802831, -0.00953581, 0.453535, -0.391317, -2.0387,  0.246545, 0.328473}}}, {{{0.403675, 0.266625, 0.837665, 0.12507,  0.729928, 0.887466, 0.795144, 0.385876, 0.773069, 0.23153,  0.367095, 0.523593, 0.316925, 0.319069, 0.26261, 0.116172,  0.775547, 0.698901, 0.0166317, 0.76896, 0.992466, 0.800873,  0.98709, 0.65864, 0.58879, 0.534248, 0.149425, 0.53357, 0.858862,  0.646782, 0.354281, 0.147694, 0.0857926, 0.415252, 0.987186,  0.624101, 0.768868, 0.096183, 0.724576, 0.507929}, {0.707944,  0.000855389, 0.596409, 0.720854, 0.0803292, 0.412065, 0.0621611},  0.571429, {0.546759, 0.553203, 0.415379, 0.217148, 0.399065}, {2,  4}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0.310906, -0.129547, 0.257531, -0.0543363, 0.284231,  0.00354923, -0.0800724, -0.330689, -0.772596, 0.511023, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0}, {0.257531, 0.284231,  0.00354954, -0.0800723, -0.330689, -0.772596,  0.511023}}}, {{{0.46741, 0.000127349, 0.229962, 0.774964,  0.698543, 0.903944, 0.505386, 0.267035, 0.705222, 0.506663,  0.797442, 0.528066, 0.704366, 0.910253, 0.0765885, 0.447737,  0.292301, 0.848092, 0.50516, 0.900977, 0.739098, 0.432713,  0.288012, 0.501912, 0.271688, 0.432586, 0.0580498, 0.726948,  0.573145, 0.528641, 0.552663, 0.459913, 0.867923, 0.0219788,  0.755221, 0.931847, 0.163557, 0.111725, 0.678633,  0.484111}, {0.173473, 0.132158, 0.83092, 0.885461, 0.0812208,  0.86047, 0.398334},  0.827411, {0.354272, 0.287325, 0.869693, 0.274748, 0.894359}, {3,  3}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.0472632, -0.242986,  0.0784643, -0.476103, 0.391061, -5.75458, 0.554761,  8.80021, -0.977023, -2.32653}, {0.0784636, 0.391059, -5.75459,  0.554764, 8.8002, -0.977021, -2.32653}}}, {{{0.419402, 0.847714,  0.519527, 0.962512, 0.255845, 0.735988, 0.840894, 0.478401,  0.384589, 0.472356, 0.667422, 0.895268, 0.252432, 0.641436,  0.78196, 0.814047, 0.391962, 0.243102, 0.954549, 0.459774,  0.104637, 0.373409, 0.679801, 0.565416, 0.685235, 0.525695,  0.160274, 0.602904, 0.42939, 0.789707, 0.31938, 0.124503,  0.0448011, 0.317351, 0.651958, 0.229235, 0.792369, 0.675915,  0.869998, 0.415189}, {0.915449, 0.295771, 0.0594049, 0.235647,  0.389999, 0.610535, 0.53371},  0.0753732, {0.787095, 0.181145, 0.744003, 0.755993, 0.662592}, {3,  3}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.123367, 1.03554,  0.157739, -0.0471723, 0.288223, 0.66643, -0.828378, -2.30797,  0.259049, 0.653172}, {0.157739, 0.288223,  0.666431, -0.828378, -2.30797, 0.259049, 0.653173}}}, {{{0.136344,  0.426652, 0.104035, 0.433356, 0.343975, 0.750737, 0.234037,  0.0181676, 0.943567, 0.317923, 0.318589, 0.0627535, 0.647797,  0.258518, 0.0829414, 0.672755, 0.0372611, 0.724808, 0.00756826,  0.88566, 0.856116, 0.980805, 0.251575, 0.223069, 0.719772,  0.554153, 0.14754, 0.789713, 0.375797, 0.803416, 0.913502,  0.771545, 0.43223, 0.485493, 0.594914, 0.708791, 0.784433,  0.226975, 0.511972, 0.0360364}, {0.504404, 0.891056, 0.521362,  0.252829, 0.927307, 0.171284, 0.967209},  0.105289, {0.137595, 0.795487, 0.163793, 0.191787, 0.36605}, {1,  4}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.487827,  0.331981, -1.16011, 2.41902, -0.0972237, 0.498921, -0.147112,  0.169144, 1.89227, -3.41907, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0}, {-1.16011, -0.0972238,  0.498921, -0.147112, 0.169144, 1.89228, -3.41907}}}, {{{0.363257,  0.6783, 0.596873, 0.657259, 0.578824, 0.451325, 0.084901,  0.621222, 0.831651, 0.949158, 0.580497, 0.470846, 0.940595,  0.427796, 0.327668, 0.543539, 0.769311, 0.460587, 0.222379,  0.405944, 0.973823, 0.296794, 0.0305921, 0.0398938, 0.610566,  0.618494, 0.433719, 0.382635, 0.0317423, 0.167169, 0.348818,  0.761413, 0.200091, 0.218011, 0.768321, 0.290567, 0.259496,  0.790215, 0.440653, 0.747029}, {0.218274, 0.516362, 0.0328345,  0.187682, 0.301191, 0.905796, 0.414341},  0.753963, {0.918556, 0.874053, 0.247172, 0.405145, 0.157142}, {3,  2}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.96023, -1.28203,  2.83745, -1.17526, -7.55545, 2.87668, 1.36467, -0.203503,  0.393107, -0.215883}, {2.83745, -7.55545, 2.87668,  1.36467, -0.203503, 0.393107, -0.215883}}}, {{{0.673962,  0.0291614, 0.636824, 0.866575, 0.414467, 0.238947, 0.196171,  0.119547, 0.924282, 0.909318, 0.977897, 0.778462, 0.40792,  0.876484, 0.790215, 0.477271, 0.502124, 0.462143, 0.036252,  0.558715, 0.628071, 0.214971, 0.631107, 0.401572, 0.954109,  0.185809, 0.994283, 0.534997, 0.539642, 0.946863, 0.798112,  0.415451, 0.61536, 0.0375442, 0.820215, 0.636989, 0.20744,  0.16106, 0.0300002, 0.159718}, {0.993748, 0.0772445, 0.483947,  0.362641, 0.199431, 0.123136, 0.298137},  0.368358, {0.664434, 0.583494, 0.351275, 0.570246, 0.248983}, {2,  0}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2.41345,  1.54446, -0.728547, -0.75822, -0.549851, -0.256782, -0.71509,  -0.449954, -0.419967, -0.0795055, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0}, {-0.728546, -0.549851, -0.256783, -0.715089, -0.449955,  -0.419967, -0.0795052}}}, {{{0.968134, 0.31373, 0.750031, 0.611994,  0.760694, 0.15267, 0.720031, 0.452276, 0.0553778, 0.453753,  0.726282, 0.851273, 0.978133, 0.969806, 0.363641, 0.651842,  0.854998, 0.671669, 0.995283, 0.987408, 0.271504, 0.320394,  0.425037, 0.738425, 0.30337, 0.0066637, 0.675006, 0.126431,  0.542676, 0.853994, 0.954976, 0.674156, 0.487299, 0.400241,  0.228693, 0.822883, 0.509165, 0.430435, 0.865052,  0.171041}, {0.869769, 0.382664, 0.438372, 0.444732, 0.445207,  0.0792941, 0.431708},  0.769726, {0.318776, 0.536618, 0.577714, 0.81475, 0.64462}, {0,  3}}, {{-0.124265, -0.229065, 0.305337, 0.490596, -0.0287917,  0.451405, -2.12906, -0.992709, 1.97678, 0.279772, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0}, {0.305337, -0.0287912, 0.451404, -2.12906, -0.992704,  1.97678, 0.279771}}}}; 

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      std::vector<float> pz (data[i].inputs.pz, data[i].inputs.pz + 5);

      NominalEmbed::DFunc dfunc (data[i].inputs.rating,
                                 pz,
                                 data[i].inputs.alpha,
                                 exp (data[i].inputs.logbeta),
                                 data[i].inputs.tau,
                                 n_labels,
                                 n_dims);

      unsigned int n_tau (NominalEmbed::num_tau (n_labels, n_dims));
      PianoVec s0 (n_dims * n_labels + n_tau, 0);
      PianoVec sprime0 (dfunc (0, s0));
      const float* megadalpha = data[i].outputs.dalpha + (data[i].inputs.rating.worker * n_dims * n_labels);

      for (unsigned int j = 0; j < n_tau; ++j)
        {
          assert (fabs (sprime0[j] - data[i].outputs.dtau[j]) <=
                  1e-4 * (1 + fabs (sprime0[j]) + fabs (data[i].outputs.dtau[j])) ||
                  (std::cerr << "(" << j << ") " << sprime0[j] << " ?= " << data[i].outputs.dtau[j] << std::endl,
                   0));
        }

      for (unsigned int j = 0; j < n_dims * n_labels; ++j)
        {
          assert (fabs (sprime0[j + n_tau] - megadalpha[j]) <=
                  1e-4 * (1 + fabs (sprime0[j + n_tau]) + fabs (megadalpha[j])) ||
                  (std::cerr << "(" << j << ") " << sprime0[j + n_tau] << " ?= " << megadalpha[j] << std::endl,
                   0));
        }
    }
}

struct UpdateTestDatum 
{ 
  struct
    {
      float             alpha[n_dims * n_labels * n_workers];
      float             tau[((2 * n_labels - n_dims - 1) * n_dims) / 2];
      float             logbeta;
      float             pz[n_labels];
      Rating            rating;
    }                                   inputs;
  struct
    {
      float             newalpha[n_dims * n_labels * n_workers];
      float             newtau[((2 * n_labels - n_dims - 1) * n_dims) / 2];
    }                                   outputs;
};

void
test_update (void)
{
  UpdateTestDatum data[] = 
    {{{{0.0492122, 0.812454, 0.383755, 0.393857, 0.140583, 0.734663,  0.126527, 0.29675, 0.655981, 0.775064, 0.506077, 0.902723,  0.0587889, 0.355945, 0.707654, 0.567155, 0.299688, 0.299831,  0.145201, 0.46831, 0.838525, 0.859683, 0.0977154, 0.95549,  0.789312, 0.0472288, 0.713961, 0.561633, 0.64873, 0.312566,  0.587433, 0.264882, 0.992749, 0.537502, 0.0813568, 0.362159,  0.93396, 0.181557, 0.373703, 0.795004}, {0.228502, 0.795747,  0.0220428, 0.130786, 0.371205, 0.00643496, 0.974814},  0.416826, {0.809572, 0.357705, 0.662248, 0.829392, 0.544689}, {3,  2}}, {{0.0492122, 0.812454, 0.383755, 0.393857, 0.140583,  0.734663, 0.126527, 0.29675, 0.655981, 0.775064, 0.506077,  0.902723, 0.0587889, 0.355945, 0.707654, 0.567155, 0.299688,  0.299831, 0.145201, 0.46831, 0.838525, 0.859683, 0.0977154,  0.95549, 0.789312, 0.0472288, 0.713961, 0.561633, 0.64873,  0.312566, 0.384741, 0.214593, 1.21228, 0.509823, 0.0382034,  0.516029, 0.929433, 0.305938, 0.404545, 0.594722}, {0.448033,  0.752594, 0.175912, 0.126259, 0.495586, 0.0372769,  0.774532}}}, {{{0.364956, 0.124746, 0.748036, 0.18253, 0.430996,  0.943189, 0.374332, 0.387526, 0.796724, 0.061463, 0.145831,  0.0608315, 0.000976605, 0.0394202, 0.0150443, 0.689627, 0.994542,  0.0646062, 0.598218, 0.880055, 0.636837, 0.402358, 0.768826,  0.335365, 0.27188, 0.277612, 0.0207904, 0.152835, 0.840884,  0.334423, 0.646458, 0.765309, 0.0441604, 0.27296, 0.500627,  0.704478, 0.0431838, 0.23354, 0.485583, 0.014851}, {0.887364,  0.411806, 0.766575, 0.118538, 0.799431, 0.139925, 0.488963},  0.097748, {0.646595, 0.299041, 0.15454, 0.45129, 0.881286}, {1,  0}}, {{0.364956, 0.124746, 0.748036, 0.18253, 0.430996, 0.943189,  0.374332, 0.387526, 0.796724, 0.061463, 0.517661,  0.612907, -0.0411983, -0.264087, -0.0667202, 0.860801, 1.09232,  0.0185179, 0.252552, 0.506401, 0.636837, 0.402358, 0.768826,  0.335365, 0.27188, 0.277612, 0.0207904, 0.152835, 0.840884,  0.334423, 0.646458, 0.765309, 0.0441604, 0.27296, 0.500627,  0.704478, 0.0431838, 0.23354, 0.485583, 0.014851}, {0.84519,  0.330041, 0.937749, 0.216314, 0.753342, -0.205741,  0.11531}}}, {{{0.25488, 0.88158, 0.950663, 0.176808, 0.211697,  0.64804, 0.46508, 0.161957, 0.163054, 0.479106, 0.577715,  0.027161, 0.751249, 0.712531, 0.459177, 0.22773, 0.611323,  0.223567, 0.361429, 0.581135, 0.312283, 0.0690273, 0.910139,  0.699849, 0.0574022, 0.187448, 0.959476, 0.523041, 0.845706,  0.539408, 0.494396, 0.361084, 0.682651, 0.0603016, 0.916681,  0.333923, 0.931402, 0.347771, 0.457504, 0.106193}, {0.0960748,  0.00779633, 0.0551764, 0.185936, 0.825208, 0.950394, 0.867729},  0.22646, {0.302167, 0.104688, 0.328321, 0.732063, 0.941083}, {3,  2}}, {{0.25488, 0.88158, 0.950663, 0.176808, 0.211697, 0.64804,  0.46508, 0.161957, 0.163054, 0.479106, 0.577715, 0.027161,  0.751249, 0.712531, 0.459177, 0.22773, 0.611323, 0.223567,  0.361429, 0.581135, 0.312283, 0.0690273, 0.910139, 0.699849,  0.0574022, 0.187448, 0.959476, 0.523041, 0.845706, 0.539408,  0.399982, 0.39162, 0.661634, -0.194332, 1.02254, 0.565004,  0.81928, 0.461356, 0.579204, -0.0143748}, {0.0750574, 0.113651,  0.286257, 0.0738128, 0.938794, 1.07209, 0.747161}}}, {{{0.422037,  0.26802, 0.815382, 0.607159, 0.490635, 0.920249, 0.357879,  0.500966, 0.170556, 0.796045, 0.261804, 0.975909, 0.162759,  0.740868, 0.075868, 0.150701, 0.212365, 0.87314, 0.849408,  0.848534, 0.107677, 0.544818, 0.117345, 0.907451, 0.68564,  0.276799, 0.301963, 0.300292, 0.195005, 0.35655, 0.944084,  0.799325, 0.0244492, 0.560505, 0.682281, 0.823416, 0.86169,  0.819637, 0.606413, 0.672716}, {0.757004, 0.541647, 0.401679,  0.639659, 0.916731, 0.856008, 0.12488},  0.337696, {0.61644, 0.661003, 0.76833, 0.393612, 0.817115}, {0,  3}}, {{0.478558, 0.367572, 0.861492, 0.60381, 0.478545, 1.04775,  0.360358, 0.249256, 0.0775356, 0.824055, 0.261804, 0.975909,  0.162759, 0.740868, 0.075868, 0.150701, 0.212365, 0.87314,  0.849408, 0.848534, 0.107677, 0.544818, 0.117345, 0.907451,  0.68564, 0.276799, 0.301963, 0.300292, 0.195005, 0.35655,  0.944084, 0.799325, 0.0244492, 0.560505, 0.682281, 0.823416,  0.86169, 0.819637, 0.606413, 0.672716}, {0.803113, 0.529558,  0.529177, 0.642139, 0.665021, 0.762988, 0.152891}}}, {{{0.636554,  0.207825, 0.711331, 0.993698, 0.774864, 0.388188, 0.104919,  0.320982, 0.12554, 0.441691, 0.347915, 0.4968, 0.583892,  0.0400118, 0.708256, 0.580069, 0.727884, 0.915131, 0.370559,  0.963629, 0.0668815, 0.146801, 0.976948, 0.146515, 0.430328,  0.938976, 0.265616, 0.152817, 0.655464, 0.550788, 0.160698,  0.831834, 0.529924, 0.109097, 0.812783, 0.335034, 0.946032,  0.0690852, 0.104528, 0.754965}, {0.733968, 0.151266, 0.00715268,  0.75702, 0.644821, 0.720938, 0.0681766},  0.491404, {0.492004, 0.0654746, 0.517389, 0.330706, 0.66017}, {0,  1}}, {{0.536188, 0.226534, 0.478284, 0.646053, 1.03166, 0.376162,  0.0748021, 0.514264, 0.232274, 0.589371, 0.347915, 0.4968,  0.583892, 0.0400118, 0.708256, 0.580069, 0.727884, 0.915131,  0.370559, 0.963629, 0.0668815, 0.146801, 0.976948, 0.146515,  0.430328, 0.938976, 0.265616, 0.152817, 0.655464, 0.550788,  0.160698, 0.831834, 0.529924, 0.109097, 0.812783, 0.335034,  0.946032, 0.0690852, 0.104528, 0.754965}, {0.500921,  0.408062, -0.0048732, 0.726904, 0.838102, 0.827673,  0.215857}}}, {{{0.53555, 0.408292, 0.517923, 0.325136, 0.589518,  0.339207, 0.413396, 0.570171, 0.37137, 0.185253, 0.679428,  0.778835, 0.220104, 0.1781, 0.922407, 0.134015, 0.499166,  0.109923, 0.431003, 0.642011, 0.433691, 0.592535, 0.100297,  0.981841, 0.898141, 0.184243, 0.582374, 0.656705, 0.308622,  0.845036, 0.168978, 0.086534, 0.937252, 0.659784, 0.48955,  0.307699, 0.717148, 0.481683, 0.567143, 0.173684}, {0.136139,  0.784291, 0.779225, 0.0358425, 0.549832, 0.88615, 0.594982},  0.453469, {0.893127, 0.577528, 0.749946, 0.284491, 0.806593}, {2,  1}}, {{0.53555, 0.408292, 0.517923, 0.325136, 0.589518, 0.339207,  0.413396, 0.570171, 0.37137, 0.185253, 0.679428, 0.778835,  0.220104, 0.1781, 0.922407, 0.134015, 0.499166, 0.109923,  0.431003, 0.642011, 0.511717, 0.544523, 0.430214, 0.976192,  0.789767, 0.0375625, 0.327803, 0.815675, 0.263624, 0.886407,  0.168978, 0.086534, 0.937252, 0.659784, 0.48955, 0.307699,  0.717148, 0.481683, 0.567143, 0.173684}, {0.466057, 0.675918,  0.632545, -0.218728, 0.708802, 0.841152, 0.636353}}}, {{{0.640276,  0.0901623, 0.794941, 0.498895, 0.923128, 0.608479, 0.227798,  0.325211, 0.705146, 0.236719, 0.0916589, 0.793538, 0.920855,  0.457494, 0.0558164, 0.243705, 0.0347046, 0.862511, 0.602347,  0.350578, 0.457177, 0.112565, 0.317856, 0.543984, 0.816901,  0.0224031, 0.522915, 0.0450896, 0.893773, 0.413924, 0.295117,  0.719879, 0.188627, 0.177205, 0.203458, 0.926341, 0.267772,  0.719712, 0.147642, 0.682636}, {0.545294, 0.775891, 0.744635,  0.227438, 0.788073, 0.95899, 0.722232},  0.704523, {0.742984, 0.0652171, 0.308308, 0.409406, 0.0231049}, {0,  1}}, {{0.85971, 0.242444, 0.569943, 0.631506, 0.721528, 0.426303,  0.25964, 0.265399, 0.880468, 0.193814, 0.0916589, 0.793538,  0.920855, 0.457494, 0.0558164, 0.243705, 0.0347046, 0.862511,  0.602347, 0.350578, 0.457177, 0.112565, 0.317856, 0.543984,  0.816901, 0.0224031, 0.522915, 0.0450896, 0.893773, 0.413924,  0.295117, 0.719879, 0.188627, 0.177205, 0.203458, 0.926341,  0.267772, 0.719712, 0.147642, 0.682636}, {0.320296, 0.574292,  0.562459, 0.259279, 0.728261, 1.13431, 0.679327}}}, {{{0.87659,  0.131102, 0.205947, 0.0967639, 0.608818, 0.41139, 0.0583058,  0.414128, 0.37575, 0.55419, 0.513012, 0.0820707, 0.599859,  0.809555, 0.285574, 0.293997, 0.640869, 0.0873229, 0.581051,  0.551014, 0.575652, 0.779015, 0.171646, 0.527909, 0.699062,  0.647913, 0.965698, 0.431145, 0.0902442, 0.236523, 0.907392,  0.0170168, 0.714494, 0.682333, 0.394381, 0.934946, 0.114636,  0.872778, 0.108807, 0.640949}, {0.527756, 0.898116, 0.00643985,  0.35611, 0.562026, 0.199054, 0.358527},  0.390412, {0.13088, 0.10881, 0.122004, 0.48302, 0.113864}, {1,  4}}, {{0.87659, 0.131102, 0.205947, 0.0967639, 0.608818, 0.41139,  0.0583058, 0.414128, 0.37575, 0.55419, 0.428765, 0.0530063,  0.711723, 0.903133, 0.369057, 0.215406, 0.494034, 0.226303,  0.616786, 0.426112, 0.575652, 0.779015, 0.171646, 0.527909,  0.699062, 0.647913, 0.965698, 0.431145, 0.0902442, 0.236523,  0.907392, 0.0170168, 0.714494, 0.682333, 0.394381, 0.934946,  0.114636, 0.872778, 0.108807, 0.640949}, {0.63962,  0.981599, -0.072152, 0.209276, 0.701005, 0.234788,  0.233625}}}, {{{0.394315, 0.439671, 0.088639, 0.178918, 0.27968,  0.566893, 0.979832, 0.537969, 0.805912, 0.781438, 0.452076,  0.448034, 0.907797, 0.774998, 0.0959657, 0.886009, 0.708743,  0.416471, 0.705553, 0.755128, 0.599933, 0.294467, 0.222534,  0.641265, 0.205618, 0.854796, 0.133895, 0.462347, 0.925938,  0.287903, 0.154063, 0.924378, 0.120026, 0.506465, 0.701987,  0.476344, 0.212229, 0.731467, 0.606021, 0.590335}, {0.900468,  0.903553, 0.0205282, 0.677934, 0.193942, 0.697935, 0.165732},  0.544039, {0.731595, 0.771997, 0.877829, 0.389977, 0.807217}, {0,  1}}, {{0.418064, 0.460548, 0.130536, 0.499539, 0.272886, 0.248513,  1.11463, 0.441064, 0.612261, 0.855225, 0.452076, 0.448034,  0.907797, 0.774998, 0.0959657, 0.886009, 0.708743, 0.416471,  0.705553, 0.755128, 0.599933, 0.294467, 0.222534, 0.641265,  0.205618, 0.854796, 0.133895, 0.462347, 0.925938, 0.287903,  0.154063, 0.924378, 0.120026, 0.506465, 0.701987, 0.476344,  0.212229, 0.731467, 0.606021, 0.590335}, {0.942365,  0.896759, -0.297852, 0.812733, 0.0970375, 0.504284,  0.239519}}}, {{{0.65197, 0.371364, 0.68799, 0.330873, 0.439741,  0.639897, 0.0819687, 0.740538, 0.936255, 0.324901, 0.181501,  0.905331, 0.0327019, 0.304373, 0.503567, 0.711389, 0.334767,  0.138641, 0.959528, 0.979793, 0.56277, 0.260812, 0.569551,  0.172576, 0.9108, 0.889449, 0.881561, 0.841703, 0.471059,  0.249552, 0.799593, 0.101165, 0.534804, 0.924651, 0.618092,  0.195833, 0.502102, 0.620277, 0.114525, 0.484445}, {0.154997,  0.604565, 0.220824, 0.585446, 0.332075, 0.693765, 0.331375},  0.703884, {0.490372, 0.222706, 0.0818237, 0.904292, 0.389207}, {1,  0}}, {{0.65197, 0.371364, 0.68799, 0.330873, 0.439741, 0.639897,  0.0819687, 0.740538, 0.936255, 0.324901, 0.614839,  0.794902, -0.0924384, 0.31494, 0.759074, 0.695155, 0.177468,  0.227435, 0.553123, 1.0071, 0.56277, 0.260812, 0.569551, 0.172576,  0.9108, 0.889449, 0.881561, 0.841703, 0.471059, 0.249552,  0.799593, 0.101165, 0.534804, 0.924651, 0.618092, 0.195833,  0.502102, 0.620277, 0.114525, 0.484445}, {0.0298566, 0.860072,  0.20459, 0.428146, 0.420869, 0.28736, 0.358678}}}}; 

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      std::vector<float> alpha (data[i].inputs.alpha,
                                data[i].inputs.alpha + n_dims * n_labels * n_workers);
      unsigned int n_tau (NominalEmbed::num_tau (n_labels, n_dims));
      std::vector<float> tau (data[i].inputs.tau, data[i].inputs.tau + n_tau);

      NominalEmbed nominal_embed (&alpha[0],
                                  &tau[0],
                                  1, // prioralpha_stddev
                                  1, // priortau_stddev
                                  n_dims, // n_dims
                                  n_workers, // n_workers
                                  n_labels, // n_labels
                                  1); // n_items

      std::vector<float> pz (data[i].inputs.pz, data[i].inputs.pz + n_labels);

      nominal_embed.update (1,
                            1,
                            0,
                            exp (data[i].inputs.logbeta),
                            pz,
                            data[i].inputs.rating);

      assert (nominal_embed.failures () == 0);

      for (unsigned int j = 0; j < n_tau; ++j)
        {
          assert (fabs (tau[j] - data[i].outputs.newtau[j]) <=
                  1e-3 * (1 + fabs (tau[j]) + fabs (data[i].outputs.newtau[j])) ||
                  (std::cerr << "(" << j << ") " << tau[j] << " ?= " << data[i].outputs.newtau[j] << std::endl,
                   0));
        }

      for (unsigned int j = 0; j < n_dims * n_labels; ++j)
        {
          assert (fabs (alpha[j] - data[i].outputs.newalpha[j]) <=
                  1e-3 * (1 + fabs (alpha[j]) + fabs (data[i].outputs.newalpha[j])) ||
                  (std::cerr << "(" << j << ") " << alpha[j] << " ?= " << data[i].outputs.newalpha[j] << std::endl,
                   0));
        }
    }
}

}

int 
main (void) 
{
  srand48 (69);

  test_logprating ();
  test_dfunc ();
  test_update ();

  return 0;
}
